import {isBoundary} from "./map-mark.boundary.js";
import {getShapeArea_LineLength} from "./map-mark.label.js";

const Cesium = window.Cesium;
const defaultProps = {
    buttonElement: {
        rectangle: null,
        polygon: null,
        circle: null,
        polyline: null,
    },
    shapeConfig: {
        shapeArea: true,
        polylineLength: true,
    }
}
export const mapMark = () => {
    const props = defaultProps;
    const state = {
        map: null,
        rangeImageLayer: null,
        marks: [],
        polylineLengthLabel: [],
        graphicLayer: null,
    }

    const installMapMarkerLayer = (map, rangeImageLayer, config) => {
        props.buttonElement = config.buttonElement;
        props.shapeConfig = config.shapeConfig;
        state.map = map;
        state.rangeImageLayer = rangeImageLayer;
        if (state.graphicLayer) {
            return;
        }
        // 创建矢量数据图层
        state.graphicLayer = new mars3d.layer.GraphicLayer()
        state.map.addLayer(state.graphicLayer);
    }

    const shapeEventCallback = (callback, type, shape, state, props) => {
        if (callback && callback instanceof Function) {
            callback(type, shape, state, props)
        }
    }

    // 给图形添加事件
    const shapeEvent = (shape, callback) => {
        getShapeArea_LineLength(shape, state, props);
        shape.on('click', () => {
            state.graphicLayer.startEditing(shape)
            shapeEventCallback(callback, 'click', shape, state, props)
        })
        shape.on('dblclick', () => {
            shapeEventCallback(callback, 'dblclick', shape, state, props)
        })
        shape.on('editMovePoint', () => {
            getShapeArea_LineLength(shape, state, props);
            state.graphicLayer.stopEditing(shape)
            isBoundary(shape, state)
            shapeEventCallback(callback, 'editMovePoint', shape, state, props)
        })
        shape.on('editMouseMove', () => {
            getShapeArea_LineLength(shape, state, props);
            shapeEventCallback(callback, 'editMouseMove', shape, state, props)
        })
        isBoundary(shape, state)
        shapeEventCallback(callback, 'init', shape, state, props)
    }

    const beginRectangle = async (_event, callback) => {
        const shape = await state.graphicLayer.startDraw({
            type: "rectangle",
            style: {
                color: "#ffff00",
                opacity: 0.4,
                outline: true,
                outlineWidth: 2,
                outlineColor: "#ffff00",
                label: {
                    text: "",
                    font_size: 18,
                    color: "#ffffff",
                    distanceDisplayCondition: true,
                    distanceDisplayCondition_far: 500000,
                    distanceDisplayCondition_near: 0
                }
            }
        })
        shapeEvent(shape, callback)
    }

    const beginPolygon = async (_event, callback) => {
        const shape = await state.graphicLayer.startDraw({
            type: "polygon",
            style: {
                color: "#29cf34",
                opacity: 0.5,
                outline: true,
                outlineWidth: 3,
                outlineColor: "#ffffff",
                label: {
                    text: "",
                    font_size: 18,
                    color: "#ffffff",
                    distanceDisplayCondition: true,
                    distanceDisplayCondition_far: 500000,
                    distanceDisplayCondition_near: 0
                }
            }
        })
        shapeEvent(shape, callback)
    }

    const beginCircle = async (_event, callback) => {
        const shape = await state.graphicLayer.startDraw({
            type: "circle",
            style: {
                color: "#ffff00",
                opacity: 0.6,
                clampToGround: false,
                outline: true,
                outlineStyle: {
                    width: 2,
                    materialOptions: {
                        color: Cesium.Color.RED, // 中心线颜色
                        dashLength: 36, // 十字长度
                        maskLength: 10, // 空隙间隔长度
                        centerPower: 0.1, // 中心宽百分比
                        dashPower: 0.2 // 虚线百分比
                    }
                },
                label: {
                    text: "",
                    font_size: 18,
                    color: "#ffffff",
                    distanceDisplayCondition: true,
                    distanceDisplayCondition_far: 500000,
                    distanceDisplayCondition_near: 0
                }
            },
            drawShowRadius: true
        })
        shapeEvent(shape, callback)
    }

    const beginPolyline = async (_event, callback) => {
        const shape = await state.graphicLayer.startDraw({
            type: "polyline",
            style: {
                color: "#55ff33",
                width: 3,
                clampToGround: false,
                label: {
                    font_size: 18,
                    color: "#ffffff",
                    distanceDisplayCondition: true,
                    distanceDisplayCondition_far: 500000,
                    distanceDisplayCondition_near: 0
                }
            }
        })
        shapeEvent(shape, callback)
    }

    const installMapMarkerButton = () => {
        const {rectangle, polygon, circle, polyline} = props.buttonElement;
        rectangle.addEventListener("click", beginRectangle);
        polygon.addEventListener("click", beginPolygon);
        circle.addEventListener("click", beginCircle);
        polyline.addEventListener("click", beginPolyline);
    }

    const getResult = async (imgURL) => {
        if (!imgURL) {
            return {
                json: state.graphicLayer.toJSON(),
                echoData: {}
            }
        }
        // 动态加载图片元数据
        const img = new Image();
        img.src = imgURL;
        await new Promise((resolve) => (img.onload = resolve));

        const viewer = state.map.viewer;
        let json = state.graphicLayer.toJSON();

        const imageRectangle = state.rangeImageLayer.options.rectangle;
        const west = Cesium.Math.toDegrees(imageRectangle.west);
        const east = Cesium.Math.toDegrees(imageRectangle.east);
        const south = Cesium.Math.toDegrees(imageRectangle.south);
        const north = Cesium.Math.toDegrees(imageRectangle.north);

        // 计算地理距离（米）
        const westNorthCarto = Cesium.Cartographic.fromDegrees(west, north);
        const eastNorthCarto = Cesium.Cartographic.fromDegrees(east, north);
        const geodesicX = new Cesium.EllipsoidGeodesic(westNorthCarto, eastNorthCarto);
        const distanceX = geodesicX.surfaceDistance;

        const westSouthCarto = Cesium.Cartographic.fromDegrees(west, south);
        const geodesicY = new Cesium.EllipsoidGeodesic(westNorthCarto, westSouthCarto);
        const distanceY = geodesicY.surfaceDistance;

        const originalImageW = img.width;
        const originalImageH = img.height;
        const horizontalMetersPerPixel = distanceX / originalImageW;
        const verticalMetersPerPixel = distanceY / originalImageH;

        const cartesianTL = mars3d.PointTrans.lonlat2cartesian([west, north, 0], 0);
        let pxInfoTL = viewer.scene.cartesianToCanvasCoordinates(cartesianTL);
        const cartesianBR = mars3d.PointTrans.lonlat2cartesian([east, south, 0], 0);
        let pxInfoBR = viewer.scene.cartesianToCanvasCoordinates(cartesianBR);

        let mapImageW = pxInfoBR.x - pxInfoTL.x;
        let mapImageH = pxInfoBR.y - pxInfoTL.y;
        let proportionW = mapImageW / originalImageW;
        let proportionH = mapImageH / originalImageH;

        let svgData = [];
        let types = ['circle', 'rectangle', 'polyline', 'polygon', 'label'];
        json.data.map((shape) => {
            if (types.includes(shape.type)) {
                let poss = shape?.positions || shape?.position;
                let svgPoints = [];
                if (poss[0] instanceof Array) {
                    svgPoints = poss.map((pos) => {
                        const cartesian = mars3d.PointTrans.lonlat2cartesian(pos, 0);
                        let info = viewer.scene.cartesianToCanvasCoordinates(cartesian);
                        info.x = (info.x - pxInfoTL.x) / proportionW;
                        info.y = (info.y - pxInfoTL.y) / proportionH;
                        return info;
                    })
                } else {
                    const cartesian = mars3d.PointTrans.lonlat2cartesian(poss, 0);
                    let info = viewer.scene.cartesianToCanvasCoordinates(cartesian);
                    info.x = (info.x - pxInfoTL.x) / proportionW;
                    info.y = (info.y - pxInfoTL.y) / proportionH;
                    svgPoints = info;
                }
                if (shape.type === 'circle') {
                    shape.style.radius = shape.style.radius / horizontalMetersPerPixel;
                }
                svgData.push({
                    ...shape,
                    svgPoints
                })
            }
        })
        return {
            json: state.graphicLayer.toJSON(),       // echoData修改了 上面变量json，不准确了；这个只用于地图回显不要互相影响
            echoData: {
                svgData,
                image: {
                    url: imgURL,
                    originalWidth: originalImageW,
                    originalHeight: originalImageH,
                }
            }
        }
    };

    const drawEcho = (data) => {
        state.graphicLayer.loadJSON(data, {flyTo: true, clear: true});
        let graphicsData = state.graphicLayer.getGraphics();
        // 筛选出label类型的图形，用来给polyline图形绑定state属性数组的，关联后续的编辑更新操作
        let labels = graphicsData.filter((shape) => shape.type === 'label');
        graphicsData.map((shape) => {
            if (shape.type === 'polyline') {
                let shapeLabels = labels.filter((label) => {
                    if (label.attr.shapeId === shape.id) {
                        return label;
                    }
                })
                if (shapeLabels && shapeLabels.length > 0) {
                    state.polylineLengthLabel.push({
                        shapeId: shape.id,
                        labels: shapeLabels
                    })
                }
            }
            if (shape.type !== 'label') {
                shapeEvent(shape);
            }
        })
    }

    return {
        installMapMarkerLayer,
        installMapMarkerButton,
        beginRectangle,
        beginPolygon,
        beginCircle,
        beginPolyline,
        getResult,
        drawEcho
    }
}